package com.allm.ai.common.strategy.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.Generation;
import org.springframework.stereotype.Component;

import com.allm.ai.common.dto.ApiRequest;
import com.allm.ai.common.dto.StreamingOutput;
import com.allm.ai.common.entity.AiModel;
import com.allm.ai.common.service.ChatModelCacheService;
import com.allm.ai.common.strategy.BaseAiModelStrategy;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;

/**
 * Kimi模型策略实现
 * 基于 Spring AI，使用 ChatModelCacheService 管理缓存
 * 实现真正的流式输出功能，支持月之暗面Kimi模型
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class KimiStrategy extends BaseAiModelStrategy {
    
    private final ChatModelCacheService cacheService;
    
    /**
     * 转换消息格式：从 Map 转换为 Spring AI Message
     */
    private List<Message> convertMessages(List<Map<String, Object>> messages) {
        if (messages == null || messages.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<Message> springMessages = new ArrayList<>();
        
        for (Map<String, Object> msg : messages) {
            String role = (String) msg.get("role");
            String content = (String) msg.get("content");
            
            if (content == null || content.trim().isEmpty()) {
                continue;
            }
            
            switch (role != null ? role.toLowerCase() : "user") {
                case "system":
                    springMessages.add(new SystemMessage(content));
                    break;
                case "user":
                    springMessages.add(new UserMessage(content));
                    break;
                case "assistant":
                    springMessages.add(new AssistantMessage(content));
                    break;
                default:
                    log.warn("未知的消息角色: {}, 作为用户消息处理", role);
                    springMessages.add(new UserMessage(content));
            }
        }
        
        return springMessages;
    }
    
    @Override
    public String callApi(AiModel model, ApiRequest request) throws Exception {
        log.info("调用 Kimi API (同步)，模型: {}, 端点: {}", model.getName(), model.getApiEndpoint());
        
        try {
            // 使用缓存服务获取简单的 ChatClient（无会话记忆）
            ChatClient chatClient = cacheService.getOrCreateSimpleChatClient(model);
            
            List<Message> messages = convertMessages(request.getMessages());
            
            if (messages.isEmpty()) {
                throw new IllegalArgumentException("消息列表不能为空");
            }
            
            // 同步调用
            return chatClient.prompt()
                    .messages(messages)
                    .call()
                    .content();
                    
        } catch (Exception e) {
            log.error("Kimi API 同步调用失败", e);
            throw new RuntimeException("Kimi API 调用失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 流式调用API - 基于 Spring AI 的真正流式实现（带会话记忆）
     */
    @Override
    public Flux<StreamingOutput> callApiStream(AiModel model, ApiRequest request) {
        log.info("调用 Kimi API (流式)，模型: {}, 端点: {}", model.getName(), model.getApiEndpoint());
        
        try {
            // 使用缓存服务获取带会话记忆的 ChatClient
            ChatClient chatClient = cacheService.getOrCreateChatClient(model);
            
            List<Message> messages = convertMessages(request.getMessages());
            
            if (messages.isEmpty()) {
                return Flux.error(new IllegalArgumentException("消息列表不能为空"));
            }
            
            // 生成会话ID（如果请求中没有提供）
            final String conversationId = (request.getConversationId() != null && !request.getConversationId().trim().isEmpty()) 
                ? request.getConversationId() 
                : "kimi-" + System.currentTimeMillis();

            // 检查是否是推理模型
            if (isReasoningModel(model)) {
                log.info("使用Kimi推理模型，将特殊处理推理过程");
                try {
                    return handleReasoningModelStream(chatClient, messages, conversationId);
                } catch (Exception e) {
                    log.error("Kimi推理模型流式调用失败", e);
                    return Flux.error(new RuntimeException("Kimi推理模型流式调用失败: " + e.getMessage(), e));
                }
            }

            // Spring AI 原生流式调用
            return chatClient.prompt()
                    .messages(messages)
                    .advisors(a -> a.param("chatMemoryConversationId", conversationId))
                    .stream()
                    .content()
                    .flatMap(output -> {
                        return splitContentByTokens(output);
                    })
                    .doOnNext(chunk -> {
                        log.debug("Kimi 流式响应片段: {}", chunk);
                    })
                    .doOnError(error -> log.error("Kimi 流式调用出错: ", error))
                    .doOnComplete(() -> log.info("Kimi 流式调用完成，会话ID: {}", conversationId))
                    .onErrorResume(error -> {
                        log.error("Kimi 流式调用失败", error);
                        return Flux.error(new RuntimeException("流式调用失败: " + error.getMessage(), error));
                    });
                    
        } catch (Exception e) {
            log.error("Kimi 流式调用初始化失败", e);
            return Flux.error(new RuntimeException("流式调用初始化失败: " + e.getMessage(), e));
        }
    }

    /**
     * 处理推理模型的流式输出 - 使用 OpenAiAssistantMessage
     * 注意：Kimi API可能不直接支持thinking内容，这里预留处理逻辑
     */
    private Flux<StreamingOutput> handleReasoningModelStream(ChatClient chatClient, List<Message> messages, String conversationId) {
        return chatClient.prompt()
            .messages(messages)
            .advisors(a -> a.param("chatMemoryConversationId", conversationId))
            .stream().chatResponse()
            .map(chatResponse -> {
                Generation generation = chatResponse.getResult();
                if (generation == null || generation.getOutput() == null) {
                    return new StreamingOutput(StreamingOutput.CONTENT, "");
                }
                
                // 检查是否是 OpenAiAssistantMessage（Kimi使用OpenAI兼容格式）
                AssistantMessage oam = (AssistantMessage) generation.getOutput();
                // if (generation.getOutput() instanceof OpenAiAssistantMessage oam) {
                // 检查推理过程 - 注意：Kimi API可能不直接支持thinking字段
                // 这里需要根据Kimi API的实际响应格式进行调整
                String thinkingContent = extractThinkingContent(oam);
                if (thinkingContent != null && !thinkingContent.trim().isEmpty()) {
                    log.info("检测到推理过程: {}", thinkingContent);

                    return new StreamingOutput(StreamingOutput.THINKING, thinkingContent);
                }
                
                // 检查最终答案
                String text = oam.getText();
                if (text != null && !text.trim().isEmpty()) {
                    log.info("检测到最终答案: {}", text);
                    return new StreamingOutput(StreamingOutput.CONTENT, text);
                }
                
                // 检查常规内容
                String content = generation.getOutput().getText();
                if (content != null && !content.isBlank()) {
                    return new StreamingOutput(StreamingOutput.CONTENT, content);
                }
                
                return new StreamingOutput(StreamingOutput.CONTENT, "done");
            })
            .filter(output -> output != null && !output.data().isBlank())
            .doOnNext(chunk -> log.debug("Kimi 推理流式响应: {}", chunk))
            .doOnError(error -> log.error("Kimi 推理流式调用出错: ", error))
            .doOnComplete(() -> log.info("Kimi 推理流式调用完成"));
    }

    /**
     * 提取思考内容
     * 注意：这个方法需要根据Kimi API的实际响应格式进行调整
     * Kimi API可能不直接支持thinking字段，需要通过其他方式获取
     */
    private String extractThinkingContent(AssistantMessage message) {
        // 这里需要根据Kimi API的实际响应格式来实现
        // 可能需要检查message的其他字段，或者通过反射获取私有字段
        // 暂时返回null，需要根据实际API响应格式调整
        
        try {
            // 示例：如果Kimi API在响应中包含thinking字段
            // 可以通过以下方式尝试获取：
            
            // 方法1：检查metadata
            if (message.getMetadata() != null) {
                Object reasoning = message.getMetadata().get("reasoning_content");
                if (reasoning != null) {
                    return reasoning.toString();
                }
            }
            
            // 方法2：通过反射获取可能的thinking字段
            // 这里需要根据Kimi API的实际响应格式来实现
            
        } catch (Exception e) {
            log.debug("无法提取thinking内容: {}", e.getMessage());
        }
        
        return null;
    }

    /**
     * 流式调用API - 简化版本（不使用会话记忆）
     */
    public Flux<String> callApiStreamSimple(AiModel model, ApiRequest request) {
        log.info("调用 Kimi API (简化流式)，模型: {}", model.getName());
        
        try {
            // 使用缓存服务获取简单的 ChatClient
            ChatClient chatClient = cacheService.getOrCreateSimpleChatClient(model);
            
            List<Message> messages = convertMessages(request.getMessages());
            
            if (messages.isEmpty()) {
                return Flux.error(new IllegalArgumentException("消息列表不能为空"));
            }
            
            // 简化的流式调用（无会话记忆）
            return chatClient.prompt()
                    .messages(messages)
                    .stream()
                    .content()
                    .doOnNext(chunk -> log.debug("Kimi 简化流式响应: {}", chunk))
                    .onErrorResume(error -> {
                        log.error("Kimi 简化流式调用失败", error);
                        return Flux.error(new RuntimeException("简化流式调用失败: " + error.getMessage(), error));
                    });
                    
        } catch (Exception e) {
            log.error("Kimi 简化流式调用初始化失败", e);
            return Flux.error(new RuntimeException("简化流式调用初始化失败: " + e.getMessage(), e));
        }
    }
    
    /**
     * 流式调用API - 自定义会话ID版本
     */
    public Flux<String> callApiStreamWithConversation(AiModel model, ApiRequest request, String conversationId) {
        log.info("调用 Kimi API (自定义会话流式)，模型: {}, 会话ID: {}", model.getName(), conversationId);
        
        try {
            ChatClient chatClient = cacheService.getOrCreateChatClient(model);
            List<Message> messages = convertMessages(request.getMessages());
            
            if (messages.isEmpty()) {
                return Flux.error(new IllegalArgumentException("消息列表不能为空"));
            }
            
            final String finalConversationId = (conversationId != null && !conversationId.trim().isEmpty()) 
                ? conversationId 
                : "kimi-custom-" + System.currentTimeMillis();
            
            return chatClient.prompt()
                    .messages(messages)
                    .advisors(a -> a.param("chatMemoryConversationId", finalConversationId))
                    .stream()
                    .content()
                    .doOnNext(chunk -> log.debug("Kimi 自定义会话流式响应: {}", chunk))
                    .doOnComplete(() -> log.info("Kimi 自定义会话流式调用完成，会话ID: {}", finalConversationId))
                    .onErrorResume(error -> {
                        log.error("Kimi 自定义会话流式调用失败", error);
                        return Flux.error(new RuntimeException("自定义会话流式调用失败: " + error.getMessage(), error));
                    });
                    
        } catch (Exception e) {
            log.error("Kimi 自定义会话流式调用初始化失败", e);
            return Flux.error(new RuntimeException("自定义会话流式调用初始化失败: " + e.getMessage(), e));
        }
    }
    
    /**
     * 清理缓存 - 委托给缓存服务
     */
    public void clearCache() {
        log.info("清理 Kimi 缓存");
        cacheService.clearAllCache();
    }
    
    /**
     * 清理特定模型的缓存
     */
    public void clearCache(AiModel model) {
        log.info("清理特定模型的缓存，模型: {}", model.getName());
        cacheService.clearCache(model);
    }
    
    /**
     * 获取缓存统计信息
     */
    public Map<String, Object> getCacheStats() {
        return cacheService.getCacheStats();
    }
    
    /**
     * 获取缓存健康状态
     */
    public Map<String, Object> getCacheHealth() {
        return cacheService.getHealthStatus();
    }
    
    /**
     * 测试模型连接
     */
    public String testConnection(AiModel model) {
        try {
            ChatClient chatClient = cacheService.getOrCreateSimpleChatClient(model);
            return chatClient.prompt()
                    .user("Hello, please respond with 'Connection successful'")
                    .call()
                    .content();
        } catch (Exception e) {
            log.error("Kimi 连接测试失败", e);
            throw new RuntimeException("连接测试失败: " + e.getMessage(), e);
        }
    }
    
    @Override
    public boolean supports(String serviceProvider) {
        return false;
        // return "月之暗面".equals(serviceProvider) || 
        //        "moonshot".equalsIgnoreCase(serviceProvider) ||
        //        "kimi".equalsIgnoreCase(serviceProvider);
    }

    /**
     * 检查是否支持流式调用
     */
    @Override
    public boolean supportsStreaming() {
        return true;
    }

    /**
     * 将内容按token拆分 - 改进版，更好地处理中文
     */
    private Flux<StreamingOutput> splitContentByTokens(String content) {
        if (content == null || content.trim().isEmpty()) {
            return Flux.empty();
        }
        
        List<StreamingOutput> chunks = new ArrayList<>();
        int targetTokensPerChunk = 2; // 每块1-2个token
        int delayMs = 50;
        
        // 使用正则表达式按单词边界和标点符号拆分
        String[] tokens = content.split("(?<=\\s|\\p{Punct})|(?=\\s|\\p{Punct})");
        
        StringBuilder currentChunk = new StringBuilder();
        int estimatedTokens = 0;
        
        for (String token : tokens) {
            if (token.trim().isEmpty()) {
                currentChunk.append(token);
                continue;
            }
            
            // 估算当前token的token数
            int tokenCount = estimateTokenCount(token);
            
            // 如果添加这个token会超过目标，先输出当前块
            if (estimatedTokens + tokenCount > targetTokensPerChunk && !currentChunk.toString().trim().isEmpty()) {
                chunks.add(new StreamingOutput(StreamingOutput.CONTENT, currentChunk.toString()));
                currentChunk.setLength(0);
                estimatedTokens = 0;
            }
            
            currentChunk.append(token);
            estimatedTokens += tokenCount;
        }
        
        // 输出剩余内容
        String remainingChunk = currentChunk.toString();
        if (!remainingChunk.trim().isEmpty()) {
            chunks.add(new StreamingOutput(StreamingOutput.CONTENT, remainingChunk));
        }
        
        return Flux.fromIterable(chunks)
            .delayElements(java.time.Duration.ofMillis(delayMs));
    }
    
    /**
     * 估算token数量 - 改进版，更好地处理中文
     */
    private int estimateTokenCount(String text) {
        if (text == null || text.trim().isEmpty()) {
            return 0;
        }
        
        int tokenCount = 0;
        boolean inEnglishWord = false;
        
        for (char c : text.toCharArray()) {
            if (isChinese(c)) {
                tokenCount += 1; // 中文字符约等于1个token
                inEnglishWord = false;
            } else if (Character.isLetter(c)) {
                if (!inEnglishWord) {
                    tokenCount += 1; // 新英文单词开始
                    inEnglishWord = true;
                }
                // 同一个英文单词内的其他字母不算token
            } else if (Character.isDigit(c)) {
                if (!inEnglishWord) {
                    tokenCount += 1; // 数字算1个token
                    inEnglishWord = true;
                }
            } else if (Character.isWhitespace(c) || isPunctuation(c)) {
                inEnglishWord = false;
                // 空格和标点符号通常不单独计算token
            } else {
                tokenCount += 1; // 其他字符算1个token
                inEnglishWord = false;
            }
        }
        
        // 最少算1个token
        return Math.max(1, tokenCount);
    }
    
}